﻿using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Net.Sockets;
using System.ComponentModel;
using System.Threading;
using InTheHand.Net;
using InTheHand.Net.Sockets;
using InTheHand.Net.Bluetooth;

namespace WiiKoonekt
{
    /// <summary>
    /// Vue correspondant aux options visibles par l'utilisateur
    /// </summary>
    public class RemoteControlForm : System.Windows.Forms.Form
    {
        // Objet de la vue
        private System.Windows.Forms.MainMenu mainMenu1;
        private System.Windows.Forms.MenuItem mnuClose;
        private System.Windows.Forms.MenuItem menuItem2;
        private System.Windows.Forms.ComboBox cmbDevices;
        private System.Windows.Forms.MenuItem mnuSearch;
        private System.Windows.Forms.MenuItem mnuConnect;
        private System.Windows.Forms.MenuItem mnuSC;
        private System.Windows.Forms.TextBox mnuTxtBox;
        private System.Windows.Forms.StatusBar stBar;
        private System.Windows.Forms.StatusBarPanel stPan;
        private System.Windows.Forms.StatusBarPanel stCon;

        private System.ComponentModel.IContainer components;

        // Composants Wii <WiimoteLib.dll>        
        //WiimoteCollection wmc = new WiimoteCollection();
        
        // Timer
        System.Windows.Forms.Timer Clock;

        private Label label1;

        // La voie <SpeechLib.dll>
        //SpVoice voix;

        // Instance du service bluetooth
        ServiceBT ServBT;

        // Inter-thread
        private delegate void InvokeStatus(string message);

        public RemoteControlForm()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            //
            // TODO: Add any constructor code after InitializeComponent call
            //
        }
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RemoteControlForm));
            this.mainMenu1 = new System.Windows.Forms.MainMenu(this.components);
            this.menuItem2 = new System.Windows.Forms.MenuItem();
            this.mnuSearch = new System.Windows.Forms.MenuItem();
            this.mnuConnect = new System.Windows.Forms.MenuItem();
            this.mnuSC = new System.Windows.Forms.MenuItem();
            this.mnuClose = new System.Windows.Forms.MenuItem();
            this.cmbDevices = new System.Windows.Forms.ComboBox();
            this.mnuTxtBox = new System.Windows.Forms.TextBox();
            this.stBar = new System.Windows.Forms.StatusBar();
            this.stPan = new System.Windows.Forms.StatusBarPanel();
            this.stCon = new System.Windows.Forms.StatusBarPanel();
            this.Clock = new System.Windows.Forms.Timer(this.components);
            this.label1 = new System.Windows.Forms.Label();
            ((System.ComponentModel.ISupportInitialize)(this.stPan)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.stCon)).BeginInit();
            this.SuspendLayout();
            // 
            // mainMenu1
            // 
            this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.menuItem2,
            this.mnuClose});
            resources.ApplyResources(this.mainMenu1, "mainMenu1");
            // 
            // menuItem2
            // 
            resources.ApplyResources(this.menuItem2, "menuItem2");
            this.menuItem2.Index = 0;
            this.menuItem2.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.mnuSearch,
            this.mnuConnect,
            this.mnuSC});
            // 
            // mnuSearch
            // 
            resources.ApplyResources(this.mnuSearch, "mnuSearch");
            this.mnuSearch.Index = 0;
            this.mnuSearch.Click += new System.EventHandler(this.mnuSearch_Click);
            // 
            // mnuConnect
            // 
            resources.ApplyResources(this.mnuConnect, "mnuConnect");
            this.mnuConnect.Index = 1;
            this.mnuConnect.Click += new System.EventHandler(this.mnuConnect_Click);
            // 
            // mnuSC
            // 
            resources.ApplyResources(this.mnuSC, "mnuSC");
            this.mnuSC.Index = 2;
            this.mnuSC.Click += new System.EventHandler(this.mnuSC_Click);
            // 
            // mnuClose
            // 
            resources.ApplyResources(this.mnuClose, "mnuClose");
            this.mnuClose.Index = 1;
            this.mnuClose.Click += new System.EventHandler(this.mnuClose_Click);
            // 
            // cmbDevices
            // 
            this.cmbDevices.AccessibleDescription = null;
            this.cmbDevices.AccessibleName = null;
            resources.ApplyResources(this.cmbDevices, "cmbDevices");
            this.cmbDevices.BackgroundImage = null;
            this.cmbDevices.Font = null;
            this.cmbDevices.Name = "cmbDevices";
            // 
            // mnuTxtBox
            // 
            this.mnuTxtBox.AccessibleDescription = null;
            this.mnuTxtBox.AccessibleName = null;
            resources.ApplyResources(this.mnuTxtBox, "mnuTxtBox");
            this.mnuTxtBox.BackgroundImage = null;
            this.mnuTxtBox.Font = null;
            this.mnuTxtBox.Name = "mnuTxtBox";
            // 
            // stBar
            // 
            this.stBar.AccessibleDescription = null;
            this.stBar.AccessibleName = null;
            resources.ApplyResources(this.stBar, "stBar");
            this.stBar.BackgroundImage = null;
            this.stBar.Font = null;
            this.stBar.Name = "stBar";
            this.stBar.Panels.AddRange(new System.Windows.Forms.StatusBarPanel[] {
            this.stPan,
            this.stCon});
            this.stBar.ShowPanels = true;
            this.stBar.SizingGrip = false;
            // 
            // stPan
            // 
            resources.ApplyResources(this.stPan, "stPan");
            this.stPan.Icon = null;
            // 
            // stCon
            // 
            resources.ApplyResources(this.stCon, "stCon");
            this.stCon.Icon = null;
            // 
            // Clock
            // 
            this.Clock.Enabled = true;
            this.Clock.Interval = 1000;
            this.Clock.Tick += new System.EventHandler(this.Timer_Tick);
            // 
            // label1
            // 
            this.label1.AccessibleDescription = null;
            this.label1.AccessibleName = null;
            resources.ApplyResources(this.label1, "label1");
            this.label1.Font = null;
            this.label1.Name = "label1";
            // 
            // RemoteControlForm
            // 
            this.AccessibleDescription = null;
            this.AccessibleName = null;
            resources.ApplyResources(this, "$this");
            this.BackgroundImage = null;
            this.Controls.Add(this.label1);
            this.Controls.Add(this.cmbDevices);
            this.Controls.Add(this.mnuTxtBox);
            this.Controls.Add(this.stBar);
            this.Font = null;
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
            this.Icon = null;
            this.Menu = this.mainMenu1;
            this.Name = "RemoteControlForm";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.RemoteControlForm_KeyUp);
            ((System.ComponentModel.ISupportInitialize)(this.stPan)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.stCon)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();

        }
        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
            Application.Run(new RemoteControlForm());
        }

        private void Form1_Load(object sender, System.EventArgs e)
        {
            //voix = new SpVoice();
            ServBT = new ServiceBT(this);
        }

        /// <summary>
        /// Rechercher et connecter les périphériques BlueTooth Wii
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mnuSC_Click(object sender, System.EventArgs e)
        {
            Thread rechercheThread = new Thread(new ThreadStart(ServBT.RechercheBluetooth));
            rechercheThread.Start();
            //rechercheThread.Join();

            /*try
            {
                wmc.Clear();
                Status("Recherche Wiimote dans le système");
                wmc.FindAllWiimotes();
            }
            catch (WiimoteNotFoundException ex)
            {
                Status("Aucune Wiimote trouvée ! " + ex.Message);
            }

            if (wmc.Count > 0)
            {
                foreach (Wiimote wm in wmc)
                {
                    try
                    {
                        Status("Wiimote connectée (" + wmc.Count + ")");
                    }
                    catch (Exception x)
                    {
                        MessageBox.Show("Cannot find a wii remote: " + x.Message);
                    }

                    this.mnuTxtBox.Text = "Wiimote Found. Connecting.";
                }
            }
            else
            {
                this.mnuTxtBox.Text = "Wiimote Not Found. Shit.";
            }*/
        }

        private void mnuSearch_Click(object sender, System.EventArgs e)
        {
            //this will take a while...
            /*Cursor.Current = Cursors.WaitCursor;
            bdi = bc.DiscoverDevices(10);
            //bind the combo
            cmbDevices.DataSource = bdi;
            cmbDevices.DisplayMember = "DeviceName";
            cmbDevices.ValueMember = "DeviceAddress";
            cmbDevices.Visible = true;
            cmbDevices.Focus();
            Cursor.Current = Cursors.Default;

            if (bdi.Length > 0)
            {
                mnuConnect.Enabled = true;
            }*/
        }

        private void mnuConnect_Click(object sender, System.EventArgs e)
        {
            if (cmbDevices.SelectedValue != null)
            {
                try
                {
                    /*BluetoothEndPoint ep = new BluetoothEndPoint((BluetoothAddress)cmbDevices.SelectedValue, BluetoothService.HumanInterfaceDevice);
                    bc.Authenticate = true;
                    bc.Pin = "";
                    mnuTxtBox.Text = (string) cmbDevices.SelectedValue;
                    bc.Connect(ep);
                    mnuConnect.Enabled = false;*/
                    this.Controls.Remove(cmbDevices);
                    this.BackColor = Color.PaleGreen;
                    this.Focus();
                }
                catch
                {
                    //error connecting
                    this.BackColor = Color.Salmon;
                }

                /*WiimoteCollection wmc = new WiimoteCollection();
                try
                {
                    wmc.FindAllWiimotes();
                }
                catch (WiimoteNotFoundException ex)
                {
                }

                if (wmc.Count > 0)
                {
                    this.mnuTxtBox.Text = "QQch";
                }
                else
                {
                    this.mnuTxtBox.Text = "Et merde";
                }*/
            }
        }

        private void mnuClose_Click(object sender, System.EventArgs e)
        {
            //bc.Close();
            this.Close();
        }

        private void RemoteControlForm_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            /*try
            {
                System.IO.Stream s = bc.GetStream();
                s.Write(BitConverter.GetBytes((short)e.KeyCode), 0, 1);
            }
            catch
            {
            }*/
        }

        public void Status(string message)
        {
            if (InvokeRequired)
            {
                IAsyncResult res = BeginInvoke(new InvokeStatus(Status), new object[] { message });
                EndInvoke(res);
            }
            else
            {
                this.stPan.Text = message;
            }
        }

        private void Timer_Tick(object sender, EventArgs eArgs)
        {
            if ((sender == Clock) && (!ServBT.getRechercheEnCours()))
            {
                int compteurClient = 0;
                ArrayList copieListeClient = (ArrayList) ServBT.getListeClient().Clone();

                foreach(BluetoothDeviceInfo clientBT in copieListeClient)
                {
                    clientBT.Refresh();

                    if (clientBT.Connected)
                    {
                        ServBT.supprimerClientEnCours(clientBT);
                        compteurClient++;
                    }
                    else
                    {
                        ServBT.supprimerClient(clientBT);
                    }
                }
                this.stCon.Text = "Connecté : " + compteurClient;
            }
        }
    }

    /// <summary>
    /// Classe regroupant tous les services Bluetooth prédéfini necessaire à la connexion de Wiimotes.
    /// </summary>
    public class ServiceBT
    {
        // Composants BlueTooth <ITH.dll>
        private BluetoothDeviceInfo[] bdi;
        private BluetoothClient bc;

        // Contient les DeviceAddress des clients en cours de connection et connecté
        private ArrayList listeClientBT;
        private ArrayList listeClientBTEnCours;

        // Forme Appelante
        private RemoteControlForm FormeAppelante;

        // Une recherche est en cours
        private Boolean rechercheEnCours;

        // Le BlueTooth est activé
        private Boolean btActif;

        /// <summary>
        /// Constructeur d'une instance du ServiceBT.
        /// </summary>
        /// <param name="r">Forme appelante</param>
        public ServiceBT(RemoteControlForm r)
        {
            btActif = false;
            rechercheEnCours = false;
            FormeAppelante = r;
            DemarrerBluetooth();
        }

        /// <summary>
        /// Accesseur sur un accès précédent à la méthode RechercheBluetooth()
        /// </summary>
        /// <returns>Booléen indiquant si une recherche est en cours</returns>
        public Boolean getRechercheEnCours()
        {
            return this.rechercheEnCours;
        }

        /// <summary>
        /// Accesseur sur la liste des clients connectés.
        /// </summary>
        /// <returns>La liste</returns>
        public ArrayList getListeClient()
        {
            return this.listeClientBT;
        }

        /// <summary>
        /// Accesseur sur la liste des clients en cours de connection.
        /// </summary>
        /// <returns>La liste des clients en cours de connection</returns>
        public ArrayList getListeClientBTEnCours()
        {
            return this.listeClientBTEnCours;
        }

        /// <summary>
        /// Méthode supprimant un client comme étant en cours de connection.
        /// </summary>
        /// <param name="client">Le BluetoothDeviceInfo du client</param>
        public void supprimerClientEnCours(BluetoothDeviceInfo client)
        {
            if (getListeClientBTEnCours().Contains(client))
            {
                getListeClientBTEnCours().Remove(client);
            }
        }

        /// <summary>
        /// Méthode supprimant un client comme étant connecté.
        /// </summary>
        /// <param name="client">Le BluetoothDeviceInfo du client</param>
        public void supprimerClient(BluetoothDeviceInfo client)
        {
            if (!getRechercheEnCours())
            {
                if (!getListeClientBTEnCours().Contains(client))
                {
                    //MessageBox.Show("Suppression : " + client.LastUsed + ", " + client.LastSeen);
                    BluetoothSecurity.RemoveDevice(client.DeviceAddress);
                    getListeClient().Remove(client);
                }
                else
                {
                    getListeClientBTEnCours().Remove(client);
                }
            }
        }

        /// <summary>
        /// Méthode métant à jour le status() de la forme appelante.
        /// </summary>
        /// <param name="message">Le message à envoyer</param>
        private void Status(string message)
        {
            FormeAppelante.Status(message);
        }

        /// <summary>
        /// Assure le démarrage du bluetooth.
        /// </summary>
        private void DemarrerBluetooth()
        {
            try
            {
                // Mise en route du BlueTooth
                BluetoothRadio.PrimaryRadio.Mode = RadioMode.Connectable;
                bc = new BluetoothClient();
                Status("BlueTooth en marche");
                btActif = true;
            }
            catch (Exception btREx)
            {
                Status("BlueTooth introuvable " + btREx.Message);
                btActif = false;
            }

            // Instanciation de la liste des clients.
            listeClientBT = new ArrayList();
            listeClientBTEnCours = new ArrayList();
        }

        /// <summary>
        /// Méthode permettant de rechercher les périphériques Bluetooth accessible.
        /// </summary>
        public void RechercheBluetooth()
        {
            // Si le bluetooth n'a pas été lancé on s'arrete
            if (!btActif) return;

            // On bloque les accès à d'autres recherches
            rechercheEnCours = true;

            Cursor.Current = Cursors.WaitCursor;
            Status("Recherche périphériques Bluetooth en cours ...");

            // Découverte des périphériques
            // FIX DiscoverDevices(maxpériphérique, tempsscan)
            bdi = bc.DiscoverDevices(10, 3);
            Cursor.Current = Cursors.Default;

            // Si aucun périphérique trouvé.
            if (bdi.Length == 0)
            {
                Status("Aucun client BT trouvé");
            }
            else
            {
                for (int btCount = 0; btCount < bdi.Length; btCount++)
                {
                    try
                    {
                        ConnecterClientBT(bdi[btCount]);
                    }
                    catch (Exception bdiEx)
                    {
                        Status("Connexion impossible : " + bdiEx.Message);
                    }
                }

                if (getListeClient().Count == 0)
                {
                    Status("Aucune Wiimote trouvée");
                }
            }

            // On rend la main sur la recherche.
            rechercheEnCours = false;
        }

        private void ConnecterClientBT(BluetoothDeviceInfo clientBT)
        {
            // Mise à jour de l'état du client (FIX)
            clientBT.Refresh();

            if ((clientBT.DeviceName == "Nintendo RVL-CNT-01") && (!clientBT.Connected))
            {
                // Si déja installé
                if (clientBT.InstalledServices.Length != 0)
                {
                    Status("Suppression Wiimote mémorisée");
                    BluetoothSecurity.RemoveDevice(clientBT.DeviceAddress);
                }
                Status("Connexion Wiimote en cours ...");
                clientBT.SetServiceState(BluetoothService.HumanInterfaceDevice, true);
                if (!listeClientBT.Contains(clientBT))
                {
                    listeClientBT.Add(clientBT);
                    listeClientBTEnCours.Add(clientBT);
                }
            }

            Status("Fin connexion");
        }
    }
}